#include "hplctimeprogram.h"
#include "modulemanager.h"
#include "modulehplccmdid.h"
#include "modulehplcdetectorparamiddefine.h"
#include "modulehplcpumpparamiddefine.h"
#include <QDebug>

HplcTimeProgram::HplcTimeProgram(QObject *parent)
    : QObject(parent)
{
    m_pump[0] = static_cast<ModuleHplcPump*>(moduleManager->find(ModuleID_HPLC_PumpA));
    m_pump[1] = static_cast<ModuleHplcPump*>(moduleManager->find(ModuleID_HPLC_PumpB));
    m_pump[2] = static_cast<ModuleHplcPump*>(moduleManager->find(ModuleID_HPLC_PumpC));
    m_pump[3] = static_cast<ModuleHplcPump*>(moduleManager->find(ModuleID_HPLC_PumpD));

    m_detector = static_cast<ModuleHplcDetector*>(moduleManager->find(ModuleID_HPLC_Detector));

    m_unit = new HplcTimeProgramUnit(this);
    m_unit->setTickPeriod(m_tickPeriod);

    m_injectProgram = new HplcInjectProgram(this);
    m_injectProgram->setTickPeriod(m_tickPeriod);
}

void HplcTimeProgram::setTickPeriod(double period_s)
{
    m_tickPeriod = period_s;
    m_injectProgram->setTickPeriod(period_s);
    m_unit->setTickPeriod(m_tickPeriod);
}

void HplcTimeProgram::setProgram(const QList<TimeProgramUnit> &list)
{
    m_program = list;
}

QList<TimeProgramUnit> HplcTimeProgram::getProgram() const
{
    return m_program;
}

void HplcTimeProgram::setLoopTimes(int times)
{
    m_loopTimes = times;
}

int HplcTimeProgram::getLoopTimes() const
{
    return m_loopTimes;
}

void HplcTimeProgram::setUsedTimeProgram(bool flag)
{
    m_isUsedTimeProgram = flag;
}

bool HplcTimeProgram::getUsedTimeProgram() const
{
    return m_isUsedTimeProgram;
}

void HplcTimeProgram::setSampleTime(double second)
{
    m_sampleTime = second;
}

double HplcTimeProgram::getSampleTime() const
{
    return m_sampleTime;
}

void HplcTimeProgram::setTotalRunTime(double second)
{
    m_totalRunTime = second;
}

double HplcTimeProgram::getTotalRunTime() const
{
    return m_totalRunTime;
}

void HplcTimeProgram::setInjectFlow(double flow)
{
    m_injectProgram->setFlow(flow);
}

double HplcTimeProgram::getInjectFlow()
{
    return m_injectProgram->getFlow();
}

void HplcTimeProgram::setInjectTime(double second)
{
    m_injectProgram->setTime(second);
}

double HplcTimeProgram::getInjectTime()
{
    return m_injectProgram->getTime();
}

bool HplcTimeProgram::isRunning()
{
    return m_isStart;
}

bool HplcTimeProgram::isPause()
{
    return m_isPause;
}

void HplcTimeProgram::start()
{
    if (!isValid())
        return;

    if (m_program.size() >= 2)
    {
        m_current = &m_program[0];
        m_next = &m_program[1];
        m_currentIndex = 1;
        qDebug() << "m_currentIndex = " << m_currentIndex;
        emit rowChanged(m_currentIndex);

        m_prevDetectorUnit.reset();
        executeRow();
        QVariant var;
        // 同步时间
        var.setValue(0);
        m_detector->setProtocolCmd(hplc::CommonCmdID_SetSyncTime, var);
        // 开始采集
        var.setValue(true);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetStartStop, var);
        startStopAllPump(true);

        m_unit->reset();
        m_unit->setUnit(m_current->pump);
        m_unit->setNextUnit(m_next->pump);
        m_unit->calculateDelta();

        m_isStart = true;
        m_isPause = false;

        m_injectProgram->stop();
    }
    else if (m_program.size() == 1)
    {
        m_current = &m_program[0];
        m_currentIndex = 0;
        emit rowChanged(m_currentIndex);

        m_prevDetectorUnit.reset();
        executeRow();
        QVariant var;
        // 同步时间
        var.setValue(0);
        m_detector->setProtocolCmd(hplc::CommonCmdID_SetSyncTime, var);
        // 开始采集
        var.setValue(true);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetStartStop, var);
        startStopAllPump(true);

        // 只有一行不用启动定时器
    }

    m_isSampleTimeout = false;
    m_isTimeProgramFinish = false;
    m_tick = 0;
}

void HplcTimeProgram::startFirstRow()
{
    if (!isValid())
        return;

    m_current = &m_program[0];
    m_currentIndex = 0;
    emit rowChanged(m_currentIndex);

    m_prevDetectorUnit.reset();
    executeRow();
    QVariant var;
    // 同步时间
    var.setValue(0);
    m_detector->setProtocolCmd(hplc::CommonCmdID_SetSyncTime, var);
    // 开始采集
    var.setValue(true);
    m_detector->setProtocolCmd(hplc::DetectorCmdID_SetStartStop, var);
    startStopAllPump(true);
}

void HplcTimeProgram::startBasicParam()
{
    QVariant var;
    // detector
    m_detector->getParam(ModuleHplcDetectorParamID_BasicParam, var);
    hplc::DetectorBasicParam param = var.value<hplc::DetectorBasicParam>();
    m_basicParam.detector.wave = param.wave.wave;
    m_basicParam.detector.wave2 = param.wave2.wave;
    m_basicParam.detector.range = param.range + 1;
    m_basicParam.detector.isZero = false;

    if (m_prevDetectorUnit.wave != m_basicParam.detector.wave
            && m_basicParam.detector.wave != 0)
    {
        var.setValue(m_basicParam.detector.wave);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetWave, var);
    }
    if (param.channel == hplc::Channel_Double)
    {
        if (m_prevDetectorUnit.wave2 != m_basicParam.detector.wave2
                && m_basicParam.detector.wave2 != 0)
        {
            var.setValue(m_basicParam.detector.wave2);
            m_detector->setProtocolCmd(hplc::DetectorCmdID_SetWave2, var);
        }
    }
    var.setValue(m_basicParam.detector.range - 1);
    m_detector->setProtocolCmd(hplc::DetectorCmdID_SetRange, var);
    if (m_basicParam.detector.isZero)
    {
        var.setValue(m_basicParam.detector.isZero);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetZero, var);
    }

    var.setValue(0);
    m_detector->setProtocolCmd(hplc::CommonCmdID_SetSyncTime, var);

    var.setValue(true);
    m_detector->setProtocolCmd(hplc::DetectorCmdID_SetStartStop, var);

    // pump
    for (int i = 0; i < HPLC_TIME_PROGRAM_PUMP_COUNT; i++)
    {
        m_pump[i]->getParam(ModuleHplcPumpParamID_BasicParam, var);
        hplc::PumpBasicParam param = var.value<hplc::PumpBasicParam>();
        m_basicParam.pump.flow = param.rate;

        var.setValue(m_basicParam.pump.flow);
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlow, var);
    }
    startStopAllPump(true);
}

void HplcTimeProgram::pause()
{
    m_isStart = false;
    m_isPause = true;
}

void HplcTimeProgram::restore()
{
    m_isStart = true;
    m_isPause = false;
}

void HplcTimeProgram::stop()
{
    m_tick = 0;
    m_unit->reset();
    m_isStart = false;
    m_isPause = false;

    m_injectProgram->stop();
}

void HplcTimeProgram::startStopAllPump(bool isStart)
{
    QVariant var;
    var.setValue(isStart);
    for (int i = 0; i < HPLC_TIME_PROGRAM_PUMP_COUNT; i++)
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetStartStop, var);
}

void HplcTimeProgram::startInjectProgram()
{
    QVariant var;
    var.setValue(m_injectProgram->getFlow());
    m_pump[3]->setProtocolCmd(hplc::PumpCmdID_SetFlow, var);
    var.setValue(true);
    m_pump[3]->setProtocolCmd(hplc::PumpCmdID_SetStartStop, var);

    m_injectProgram->start();
    m_isStart = true;
    m_isPause = false;
}

void HplcTimeProgram::onTick()
{
    if (!m_isStart || m_isPause)
        return;

//    qDebug() << "onTick";

    // 如果注样程序正在运行，则先运行完注样程序
    if (m_injectProgram->isStart())
    {
        m_injectProgram->onTick();
        if (m_injectProgram->isTimeout()) // 注样程序运行完成
        {
            m_injectProgram->stop();
            emit injectProgramFinished();

            QVariant var;
            var.setValue(false);
            m_pump[3]->setProtocolCmd(hplc::PumpCmdID_SetStartStop, var);

            // 注样程序运行完，启动时间程序
            start();
        }
        return;
    }

    m_tick += m_tickPeriod;

//    qDebug() << "m_tick = " << m_tick;

    // 总运行时间到
    if (m_tick >= m_totalRunTime)
    {
        m_isStart = false;
        m_isPause = false;
        emit totalRunTimeout();

        // 停所有泵
        startStopAllPump(false);

        // 关灯
        QVariant var;
        var.setValue(false);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetLamp, var);

        return;
    }

    // 采集时间到
    if (m_tick >= m_sampleTime && !m_isSampleTimeout)
    {
        m_isSampleTimeout = true;
        emit sampleTimeout();

        // 停止采集
        QVariant var;
        var.setValue(false);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetStartStop, var);
    }

    // 时间程序是否完成
    if (m_isUsedTimeProgram && !m_isTimeProgramFinish)
    {
        m_unit->onTick();
        if (m_unit->isFinished())
        {
            qDebug() << "next";
            next();
            executeRow();
        }
        else
        {
            execute();
        }
    }
}

bool HplcTimeProgram::isValid()
{
    return (m_program.size() >= 1 && qFuzzyIsNull(m_program.at(0).pump.time));
}

void HplcTimeProgram::next()
{
    m_currentIndex++;
    if (m_currentIndex >= m_program.size())
    {
        if (m_loopTimes <= 0)
        {
            m_isTimeProgramFinish = true;
            emit timeProgramFinished();

            // 执行第一行程序
            m_currentIndex = 0;
            m_current = &m_program[0];
            emit rowChanged(m_currentIndex);
            executeRow();

            // 修改流速百分比为100%
            QVariant var;
            for (int i = 0; i < HPLC_TIME_PROGRAM_PUMP_COUNT; i++)
            {
                var.setValue(100);
                m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlowPercent, var);
            }
        }
        else // 重头来过
        {
            if (m_loopTimes)
            {
                m_loopTimes--;
                emit loopTimesChanged(m_loopTimes);
            }

            qDebug() << "restart";
            m_currentIndex = 0;
            m_current = &m_program[0];
            if (m_program.size() >= 2)
            {
                m_currentIndex = 1;
                m_next = &m_program[m_currentIndex];
                emit rowChanged(m_currentIndex);

                executeRow();

                m_unit->reset();
                m_unit->setUnit(m_current->pump);
                m_unit->setNextUnit(m_next->pump);
                m_unit->calculateDelta();
            }
            else if (m_program.size() == 1)
            {
                emit rowChanged(m_currentIndex);
                executeRow();
            }
        }
    }
    else
    {
        m_current = m_next;
        m_next = &m_program[m_currentIndex];
        emit rowChanged(m_currentIndex);

        m_unit->reset();
        m_unit->setUnit(m_current->pump);
        m_unit->setNextUnit(m_next->pump);
        m_unit->calculateDelta();
    }
}

void HplcTimeProgram::executeRow()
{
    QVariant var;
    // pump
    for (int i = 0; i < HPLC_TIME_PROGRAM_PUMP_COUNT; i++)
    {
        // 设置流速
        var.setValue(m_current->pump.flow * m_current->pump.percent[i] / 100.0);
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlow, var);
        // 设置流速百分比
        var.setValue((quint8)(m_current->pump.percent[i] + 0.5));
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlowPercent, var);
    }
    emit statusChanged(m_current->pump);

    // detector
    // 波长1
    if (m_prevDetectorUnit.wave != m_current->detector.wave
            && m_current->detector.wave != 0)
    {
        m_prevDetectorUnit.wave = m_current->detector.wave;

        var.setValue(m_current->detector.wave);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetWave, var);
    }
    // 波长2
    m_detector->getParam(ModuleHplcDetectorParamID_BasicParam, var);
    hplc::DetectorBasicParam param = var.value<hplc::DetectorBasicParam>();
    if (param.channel == hplc::Channel_Double)
    {
        if (m_prevDetectorUnit.wave2 != m_current->detector.wave2
                && m_current->detector.wave2 != 0)
        {
            m_prevDetectorUnit.wave2 = m_current->detector.wave2;

            var.setValue(m_current->detector.wave2);
            m_detector->setProtocolCmd(hplc::DetectorCmdID_SetWave2, var);
        }
    }
    // 设置量程
    if (m_prevDetectorUnit.range != m_current->detector.range
            && m_current->detector.range != 0)
    {
        m_prevDetectorUnit.range = m_current->detector.range;

        var.setValue(m_current->detector.range - 1);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetRange, var);
    }
    // 归零
    m_prevDetectorUnit.isZero = m_current->detector.isZero;
    if (m_current->detector.isZero)
    {
        var.setValue(m_current->detector.isZero);
        m_detector->setProtocolCmd(hplc::DetectorCmdID_SetZero, var);
    }
}

void HplcTimeProgram::execute()
{
    QVariant var;
    // pump
    PumpUnit pumpUnit = m_unit->getCurrent();
    emit statusChanged(pumpUnit);
    for (int i = 0; i < HPLC_TIME_PROGRAM_PUMP_COUNT; i++)
    {
        // 设置流速
        var.setValue(pumpUnit.flow * pumpUnit.percent[i] / 100.0);
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlow, var);
        // 设置流速百分比
        var.setValue((quint8)(pumpUnit.percent[i] + 0.5));
        m_pump[i]->setProtocolCmd(hplc::PumpCmdID_SetFlowPercent, var);

        qDebug() << pumpUnit.flow * pumpUnit.percent[i] / 100.0 << (quint8)(pumpUnit.percent[i] + 0.5);
    }
}
